#ifndef TEXTBLOCK_H
#define TEXTBLOCK_H

#include "font.h"

namespace Library
{

class PLIBEXP TextBlock
{
	public:
		enum HorizontalPosition { 
			HP_LEFT_TEXT,		HP_LEFT_GFX,
			HP_CENTER_TEXT,		HP_CENTER_GFX,
			HP_RIGHT_TEXT,		HP_RIGHT_GFX
		};

// Justification has not yet been implemented.
		enum Justification {
			HJ_LEFT_TEXT,		HJ_LEFT_GFX,
			HJ_CENTER_TEXT,		HJ_CENTER_GFX,
			HJ_RIGHT_TEXT,		HJ_RIGHT_GFX
		};

		enum VerticalPosition {
			VP_TOP_TEXT,		VP_TOP_GFX,
			VP_CENTER_TEXT,		VP_CENTER_GFX,
			VP_BOTTOM_TEXT,		VP_BOTTOM_GFX
		};

						TextBlock();
						TextBlock(const String & aFont, uint32 width,
							uint32 height);
						TextBlock(const String & aFont, uint32 width,
							uint32 height, const String & text);

						// Deprecated
						TextBlock(const String & aFont, uint32 width,
							uint32 height, const uint16* text);

						~TextBlock();

		pCBitmap		bitmap();
		uint32			bitmapHeight();
		uint32			bitmapWidth();

		enum BlockSize { BS_AUTOSIZE = 0 };
		void			blockHeight(uint32 height);
		uint32			blockHeight();

		void			blockWidth(uint32 width);
		uint32			blockWidth();

		void			blockSize(uint32 width, uint32 height);

		void			draw(pCFrame pFrame, int32 x, int32 y);

		void			font(const String & aFont);
		Font *			font();
		const String &	fontName();

		enum FontSize { FS_AUTOSIZE = 0, FS_FULLSIZE = 0xffffffff };
		void			fontSize(uint32 size);
		void			fontSize(FontSize size);
		uint32			fontSize();
		uint32			fontSizeRendered();

		void			horizontalPosition(HorizontalPosition method);
		HorizontalPosition horizontalPosition();

		void			ignoreLineBreaks(bool8 trueFalse);
		bool8			ignoreLineBreaks();

// Justification has not yet been implemented.
		void			justification(Justification method);
		Justification	justification();

		void			text(const String & text);

		// Deprecated
		void			text(const uint16 * text);
		// Deprecated
		const uint16 *	text();

		void			verticalPosition(VerticalPosition method);
		VerticalPosition verticalPosition();

        // kharmon.  03-24-06.  #10515.  7 Stud Poker.  Used to figure
        // out how much of the generated bitmap is actually text vs. just
        // empty space.
        int32 getTextWidth()  { return mIB.ibTextWidth; }
        int32 getTextHeight() { return mIB.ibTextHeight; }

		// psharpless 11/28/06 - Case: 17326
		int32 getNumLines()	  { return mIB.ibLinesValid; }

	protected:
		uint16 *	preprocessText(const uint16 * text);
		uint16 *	skipWhitespace(uint16 * text);
		uint16 *	findWord(uint16 * text, uint16 ** start, uint16 ** end);
		uint32		wordCount(uint16 * text);
		void		formatText();
		void		buildBitmap();

	protected:
		struct Line;

		struct PLIBEXP IncrementalBuild
		{
			enum State	{ INVALID = 0, VALID = 1 };
			State		ibState;
			uint16*		ibText;
			Line *		ibLines;
			uint32		ibLinesTotal;
			uint32		ibLinesValid;
			uint32		ibLineFirst;
			uint32		ibLineLast;
			uint32		ibWidth;
			uint32		ibHeight;
			float		ibScale;
			int32		ibGraphicWidth;
			int32		ibGraphicHeight;
			int32		ibTextWidth;
			int32		ibTextHeight;
		};

		enum Flags {
			AUTOBREAK_LINES		= (1L << 0),
			IGNORE_LINE_BREAKS	= (1L << 1),
			SHRINK_TO_FIT		= (1L << 2),
			USE_ELLIPSIS		= (1L << 3)
		};

		Font *				mFont;
		uint16*				mText;
		String				mFontName;
		pCBitmap			mBitmap;
		uint32				mBitmapHeight;
		uint32				mBitmapWidth;
		uint32				mBlockHeight;
		uint32				mBlockWidth;
		uint32				mFontSize;
		uint32				mFontSizeRendered;
		uint32				mFlags;
		Justification		mJustification;
		HorizontalPosition	mHorizontalPosition;
		VerticalPosition	mVerticalPosition;
		IncrementalBuild	mIB;

	private:
		void		initialize();

	// prohibited
	private:
		TextBlock(TextBlock &);
		TextBlock & operator=(TextBlock &);
};

//----------------------------------------------------------------------------
// Structs, protected
//
struct TextBlock::Line
{
	uint16* start;
	uint16*	end;
	int32	glyphWidth;
	int32	glyphHeight;
	int32	glyphLeft;
	int32	glyphRight;
	int32	glyphTop;
	int32	glyphBottom;
	int32	textWidth;
	int32	textHeight;
	int32	textAbcA;
	int32	textAbcC;
	bool8	validLine;

	void	calculateMetrics(Font * aFont);
	void	paint(Font * aFont, int32 x, int32 y, pCBitmap bitmap);
};

//----------------------------------------------------------------------------
// Inline, public
//
#define FLAG_TOGGLE(variable, flag, conditional)							\
		do {																\
			if (conditional)												\
				variable |= (flag);											\
			else															\
				variable &= ~(flag);										\
		} while (0);

#define FLAG_CHECK(variable, flag)											\
		((variable & (flag)) != 0)

inline void
TextBlock::ignoreLineBreaks(bool8 trueFalse)
{
	FLAG_TOGGLE(mFlags, IGNORE_LINE_BREAKS, trueFalse);
}

inline bool8
TextBlock::ignoreLineBreaks()
{
	return FLAG_CHECK(mFlags, IGNORE_LINE_BREAKS);
}

// Not currently implemented.
#if 0
inline void
TextBlock::shrinkToFit(bool8 trueFalse)
{
	FLAG_TOGGLE(mFlags, SHRINK_TO_FIT, trueFalse);
}

inline bool8
TextBlock::shrinkToFit()
{
	return FLAG_CHECK(mFlags, SHRINK_TO_FIT);
}

inline void
TextBlock::useEllipsis(bool8 trueFalse)
{
	FLAG_TOGGLE(mFlags, USE_ELLIPSIS, trueFalse);
}

inline bool8
TextBlock::useEllipsis()
{
	return FLAG_CHECK(mFlags, USE_ELLIPSIS);
}

inline void
TextBlock::wordWrap(bool8 trueFalse)
{
	FLAG_TOGGLE(mFlags, WORDWRAP, trueFalse);
}

inline bool8
TextBlock::wordWrap()
{
	return FLAG_CHECK(mFlags, WORDWRAP);
}
#endif

}; // namespace Library

#endif
